/* Copyright (C) 2011 The University of Michigan This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Please send inquiries to powertutor@umich.edu */ package vn.cybersoft.obs.andriod.batterystats2.util; import android.app.ActivityManager; import java.util.Arrays; import java.util.BitSet; import java.util.List; /* This detector looks for transitions where one app leaves the foreground and * another enters the foreground to detect apps that are legitimately in the * foreground. If no application is known to be legitimate system is returned. */ public class ForegroundDetector { int lastSize; int[] lastUids; int nowSize; int[] nowUids; private BitSet validated; private ActivityManager activityManager; public ForegroundDetector(ActivityManager activityManager) { lastSize = nowSize = 0; lastUids = new int[10]; nowUids = new int[10]; validated = new BitSet(1 << 16); validated.set(android.os.Process.myUid()); this.activityManager = activityManager; } // Figure out what uid should be charged for screen usage. public int getForegroundUid() { SystemInfo sysInfo = SystemInfo.getInstance(); List<ActivityManager.RunningAppProcessInfo> appProcs = activityManager.getRunningAppProcesses(); // Move the last iteration to last and resize the other array if needed. int[] tmp = lastUids; lastUids = nowUids; lastSize = nowSize; if(tmp.length < appProcs.size()) { tmp = new int[appProcs.size()]; } nowUids = tmp; // Fill in the uids from appProcs. nowSize = 0; for(ActivityManager.RunningAppProcessInfo app : appProcs) { if(app.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { int uid = sysInfo.getUidForPid(app.pid); if(SystemInfo.AID_APP <= uid && uid < 1 << 16) { nowUids[nowSize++] = uid; } } } Arrays.sort(nowUids, 0, nowSize); // Find app-exit app-enter transitions. int appExit = -1; int appEnter = -1; int indNow = 0; int indLast = 0; while(indNow < nowSize && indLast < lastSize) { if(nowUids[indNow] == lastUids[indLast]) { indNow++; indLast++; } else if(nowUids[indNow] < lastUids[indLast]) { appEnter = nowUids[indNow++]; } else { appExit = lastUids[indLast++]; } } if(indNow < nowSize) appEnter = nowUids[indNow]; if(indLast < lastSize) appExit = lastUids[indLast]; // Found an interesting transition. Validate both applications. if(appEnter != -1 && appExit != -1) { validated.set(appEnter); validated.set(appExit); } // Now find a valid application now. Hopefully there is only one. If there // are none return system. If there are several return the one with the // highest uid. for(int i = nowSize - 1; i >= 0; i--) { if(validated.get(nowUids[i])) { return nowUids[i]; } } return SystemInfo.AID_SYSTEM; } }